//
// This code was created by Jeff Molofee '99 (ported to Linux/GLUT by Richard Campbell '99)
//
// If you've found this code useful, please let me know.
//
// Visit me at www.demonews.com/hosted/nehe
// (email Richard Campbell at ulmont@bellsouth.net)
//

#ifndef _LINUX_GL_LIBRARIES
#define _LINUX_GL_LIBRARIES

#include <GL/glut.h>    				// Header File For The GLUT Library
#include <GL/gl.h>						// Header File For The OpenGL32 Library
#include <GL/glu.h>						// Header File For The GLu32 Library

#endif

#include <cstdlib>
#include <cstdio>
#include <iostream>
#include <cmath>

#include "texture.h"
#include "Player.h"
#include "Figures.h"

#define ESCAPE 27						// ascii code for the escape key

#define STAR_NUM 50 	                        // Number Of Stars To Draw

using namespace std;

typedef struct {
	float x, y, z;						// 3D Coordinates
	float u, v;                         // Texture Coordinates
} VERTEX;                               // Call It VERTEX

typedef struct {
	VERTEX vertex[3];					// Array Of Three Vertices
} TRIANGLE;								// Call It TRIANGLE

typedef struct {
	int numtriangles;                   // Number Of Triangles In Sector
	TRIANGLE* triangle;                 // Pointer To Array Of Triangles
} SECTOR;								// Call It SECTOR

int window;

bool* keyStates = new bool[256];
bool* specialKeyStates = new bool[256];

Player *player;
Figures *fig1;

GLuint loop;
GLuint texture[6];
GLuint filter=0;

bool light = true;
bool blend = true;

bool fullscreen = true;
bool lights[10];

GLfloat xrot;
GLfloat yrot;
GLfloat xspeed;
GLfloat yspeed;
GLfloat xpos;
GLfloat zpos;

GLfloat heading;

GLfloat walkbias = 0.0f;
GLfloat walkbiasangle = 0.0f;

GLfloat lookupdown = 0.0f;
const float piover180 = 4*atan(1)/180.0;

GLfloat camx = 0.0f;
GLfloat camy = 0.0f;
GLfloat camz = 0.0f;
GLfloat therotate;

GLfloat z=0.0f;

GLfloat LightAmbient1[]= { 0.3f, 0.5f, 0.8f, 1.0f };	// Ambient Light Values
GLfloat LightDiffuse1[]= { 1.0f, 1.0f, 1.0f, 1.0f };    // Diffuse Light Values
GLfloat LightPosition1[]= { 0.0f, 0.0f, 5.0f, 1.0f };   // Light Position

GLfloat LightPosition2[]={0.0, 0.5,-1.0};
GLfloat LightDiffuse2[]={0.0,0.3,0.9,0.5};

GLfloat LightPosition3[]={0.8,0.8,0.0,1.0};

GLfloat flash_pos[]={0.0,0.5,0.0,0.0};
GLfloat flash_see[]={0.0,0.5,0.0,0.0};

GLfloat mat_glass[]={0.1,0.1,0.5,0.5};
GLfloat mat_crate[]={1.0,1.0,1.0,1.0};
GLfloat mat_crate_amb[]={0.3,0.3,0.3,1.0};
GLfloat empty[]={0.0,0.0,0.0,0.0};					// no reaction with light

GLfloat color_glass[]={0.3,0.5,0.9,0.5};

GLuint fogMode[]= { GL_EXP, GL_EXP2, GL_LINEAR };   // Storage For Three Types Of Fog
GLuint fogfilter= 0;                    			// Which Fog To Use
GLfloat fogColor[4]= {0.5f, 0.5f, 0.5f, 1.0f};      // Fog Color

SECTOR sector1;

char files[3][16] = {
		"Data/world.txt",
		"Data/crate.bmp",
		"Data/glass.bmp"
};

// degrees to radians...2 PI radians = 360 degrees
float rad(float angle){
	return angle * piover180;
}

// helper for SetupWorld.  reads a file into a string until a nonblank, non-comment line
// is found ("/" at the start indicating a comment); assumes lines < 255 characters long.
void readstr(FILE *f,char *string) {
	do {
		fgets(string, 255, f);
	} while ((string[0] == '/') || (string[0] == '\n'));
	return;
}

// loads the world from a text file.
void SetupWorld() {
	float x,y,z,u,v;
	int numtriangles;
	FILE *filein;
	char oneline[255];

	filein = fopen(files[0], "rt");

	readstr(filein,oneline);
	sscanf(oneline,"NUMPOLLIES %d\n", &numtriangles);

	sector1.numtriangles = numtriangles;                    	// Define The Number Of Triangles In Sector 1
	sector1.triangle = (TRIANGLE *) malloc(sizeof(TRIANGLE) * numtriangles);              // Allocate Memory For numtriangles And Set Pointer

	// Step Through Each Triangle In Sector
	for (int tri = 0; tri < numtriangles; tri++) {	// Loop Through All The Triangles
		// Step Through Each Vertex In Triangle
		for (int vert = 0; vert < 3; vert++) {		// Loop Through All The Vertices
			readstr(filein,oneline);							// Read String To Work With
			// Read Data Into Respective Vertex Values
			sscanf(oneline, "%f %f %f %f %f", &x, &y, &z, &u, &v);	// Store Values Into Respective Vertices
			sector1.triangle[tri].vertex[vert].x = x;   // Sector 1, Triangle triloop, Vertice vertloop, x Value=x
			sector1.triangle[tri].vertex[vert].y = y;   // Sector 1, Triangle triloop, Vertice vertloop, y Value=y
			sector1.triangle[tri].vertex[vert].z = z;   // Sector 1, Triangle triloop, Vertice vertloop, z Value=z
			sector1.triangle[tri].vertex[vert].u = u;   // Sector 1, Triangle triloop, Vertice vertloop, u Value=u
			sector1.triangle[tri].vertex[vert].v = v;   // Sector 1, Triangle triloop, Vertice vertloop, v Value=v
		}
	}

	fclose(filein);
}

/*
 * getint and getshort are help functions to load the bitmap byte by byte on
 * SPARC platform (actually, just makes the thing work on platforms of either
 * endianness, not just Intel's little endian)
 */
unsigned int getInt(FILE *fp) {
	int c, c1, c2, c3;

	// get 4 bytes
	c = getc(fp);
	c1 = getc(fp);
	c2 = getc(fp);
	c3 = getc(fp);

	return ((unsigned int) c) +
			(((unsigned int) c1) << 8) +
			(((unsigned int) c2) << 16) +
			(((unsigned int) c3) << 24);
}

unsigned int getShort(FILE *fp) {
	int c, c1;

	//get 2 bytes
	c = getc(fp);
	c1 = getc(fp);

	return ((unsigned int) c) + (((unsigned int) c1) << 8);
}

bool LoadGLTextures(char *filename, int lvl) {
	// Load Texture
	Image *image1;

	// allocate space for texture
	image1 = (Image *) malloc(sizeof(Image));
	if (image1 == NULL) {
		cout << "Error allocating space for image" << endl;
		return false;
	}

	if (!ImageLoad(filename, image1)) {
		return false;
	}

	glGenTextures(3, &texture[lvl+0]);				// Create Texture

	// Create Nearest Filtered Texture
	glBindTexture(GL_TEXTURE_2D, texture[lvl+0]);   // 2d texture (x and y size)
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); // less cpu, less quality, more frame per seconds
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
	glTexImage2D(GL_TEXTURE_2D, 0, 3, image1->sizeX, image1->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, image1->data);

	// Create Linear Filtered Texture
	glBindTexture(GL_TEXTURE_2D, texture[lvl+1]);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
	glTexImage2D(GL_TEXTURE_2D, 0, 3, image1->sizeX, image1->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, image1->data);

	// Create MipMapped Texture
	glBindTexture(GL_TEXTURE_2D, texture[lvl+2]);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);
	gluBuild2DMipmaps(GL_TEXTURE_2D, 3, image1->sizeX, image1->sizeY, GL_RGB, GL_UNSIGNED_BYTE, image1->data);

	if (image1){
		if (image1->data){
			free(image1->data);
		}
		free(image1);
	}
	return true;
}

/* A general OpenGL initialization function.  Sets all of the initial parameters. */
bool InitGL(int Width, int Height)	        // We call this right after our OpenGL window is created.
{
	LoadGLTextures(files[1],0);
	LoadGLTextures(files[2],3);

	glEnable(GL_TEXTURE_2D);

	glBlendFunc(GL_SRC_ALPHA, GL_ONE);		// Set the blending function for translucency (note off at init time)
	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);	// This Will Clear The Background Color To Black
	glClearDepth(1.0);						// Enables Clearing Of The Depth Buffer
	glDepthFunc(GL_LESS);					// type of depth test to do.
	glEnable(GL_DEPTH_TEST);				// enables depth testing.

	// set up lights.
	glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient1);
	glLightfv(GL_LIGHT2, GL_DIFFUSE, LightDiffuse1);
	glLightfv(GL_LIGHT3, GL_POSITION, LightPosition1);

	glLightfv(GL_LIGHT4, GL_POSITION, LightPosition2);
	glLightfv(GL_LIGHT5, GL_DIFFUSE, LightDiffuse2);

	// Half Life flash
	glLightfv(GL_LIGHT6,GL_AMBIENT, empty);
	glLightfv(GL_LIGHT6,GL_DIFFUSE, LightPosition3);
	glLightfv(GL_LIGHT6,GL_SPECULAR, empty);
	glLightfv(GL_LIGHT6,GL_POSITION, flash_pos);
	glLightfv(GL_LIGHT6,GL_SPOT_DIRECTION, flash_see);
	glLightf(GL_LIGHT6,GL_SPOT_EXPONENT, 0.0);
	glLightf(GL_LIGHT6,GL_SPOT_CUTOFF, 30.0);				// 30°
	glLightf(GL_LIGHT6,GL_CONSTANT_ATTENUATION, 2.0);
	glLightf(GL_LIGHT6,GL_LINEAR_ATTENUATION, 1.0);
	glLightf(GL_LIGHT6,GL_QUADRATIC_ATTENUATION, 0.5);

	glDisable(GL_LIGHT0);
	glEnable(GL_LIGHT1);
	glEnable(GL_LIGHT2);
	glEnable(GL_LIGHT3);
	glEnable(GL_LIGHT4);
	glEnable(GL_LIGHT5);
	glEnable(GL_LIGHT6);

	glEnable(GL_LIGHTING);

	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	glShadeModel(GL_SMOOTH);				// Enables Smooth Color Shading

	glClearColor(0.5f,0.5f,0.5f,1.0f);          // We'll Clear To The Color Of The Fog ( Modified )

	glFogi(GL_FOG_MODE, fogMode[fogfilter]);    // Fog Mode
	glFogfv(GL_FOG_COLOR, fogColor);            // Set Fog Color
	glFogf(GL_FOG_DENSITY, 0.35f);              // How Dense Will The Fog Be
	glHint(GL_FOG_HINT, GL_DONT_CARE);          // Fog Hint Value
	glFogf(GL_FOG_START, 1.0f);             	// Fog Start Depth
	glFogf(GL_FOG_END, 5.0f);               	// Fog End Depth
	glEnable(GL_FOG);                   		// Enables GL_FOG

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();						// Reset The Projection Matrix

	gluPerspective(45.0f,(GLfloat)Width/(GLfloat)Height,0.1f,100.0f);	// Calculate The Aspect Ratio Of The Window

	glMatrixMode(GL_MODELVIEW);

	return true;
}

/* The function called when our window is resized (which shouldn't happen, because we're fullscreen) */
GLvoid ReSizeGLScene(GLsizei Width, GLsizei Height)
{
	if (Height==0)							// Prevent A Divide By Zero If The Window Is Too Small
		Height=1;

	glViewport(0, 0, Width, Height);		// Reset The Current Viewport And Perspective Transformation

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

	gluPerspective(45.0f,(GLfloat)Width/(GLfloat)Height,0.1f,100.0f);	// Calculate The Aspect Ratio Of The Window
	glMatrixMode(GL_MODELVIEW);
}

void keyOperations();
void keySpecialoperations();

/* The main drawing function. */
GLvoid DrawGLScene() {

	keyOperations();
	keySpecialoperations();

	GLfloat x_m, y_m, z_m, u_m, v_m;
	GLfloat xtrans, ytrans, ztrans;
	GLfloat sceneroty;
	int numtriangles;

	// calculate translations and rotations.
	xtrans = -player->getXpos();
	ztrans = -player->getZpos();
	ytrans = -player->getWalkbiasangle()-0.25f;
	sceneroty = 360.0f - player->getHeadingH();

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);		// Clear The Screen And The Depth Buffer
	glLoadIdentity();

	glRotatef(player->getHeadingV(), 1.0f, 0, 0);
	glRotatef(sceneroty, 0, 1.0f, 0);

	glTranslatef(xtrans, ytrans, ztrans);

	glBindTexture(GL_TEXTURE_2D, texture[0+filter]);    // pick the texture.

	glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,mat_crate_amb);
	glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,mat_crate_amb);
	glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,mat_crate);
	glMaterialfv(GL_FRONT_AND_BACK,GL_SHININESS,mat_crate);
	glMaterialfv(GL_FRONT_AND_BACK,GL_EMISSION,empty);

	numtriangles = sector1.numtriangles;

	for (int loop=0; loop<numtriangles; loop++) {        // loop through all the triangles
		glBegin(GL_TRIANGLES);

		glColor4f(1.0,1.0,1.0,1.0);

		glNormal3f( 0.0f, 0.0f, 1.0f);

		x_m = sector1.triangle[loop].vertex[0].x;
		y_m = sector1.triangle[loop].vertex[0].y;
		z_m = sector1.triangle[loop].vertex[0].z;
		u_m = sector1.triangle[loop].vertex[0].u;
		v_m = sector1.triangle[loop].vertex[0].v;
		glTexCoord2f(u_m,v_m);
		glVertex3f(x_m,y_m,z_m);

		x_m = sector1.triangle[loop].vertex[1].x;
		y_m = sector1.triangle[loop].vertex[1].y;
		z_m = sector1.triangle[loop].vertex[1].z;
		u_m = sector1.triangle[loop].vertex[1].u;
		v_m = sector1.triangle[loop].vertex[1].v;
		glTexCoord2f(u_m,v_m);
		glVertex3f(x_m,y_m,z_m);

		x_m = sector1.triangle[loop].vertex[2].x;
		y_m = sector1.triangle[loop].vertex[2].y;
		z_m = sector1.triangle[loop].vertex[2].z;
		u_m = sector1.triangle[loop].vertex[2].u;
		v_m = sector1.triangle[loop].vertex[2].v;
		glTexCoord2f(u_m,v_m);
		glVertex3f(x_m,y_m,z_m);

		glEnd();
	}

	glBindTexture(GL_TEXTURE_2D, texture[3+filter]);    // pick the texture.

	glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE);


	// flash repositioning
	GLfloat pos[]={player->getXpos(),player->getYpos(),player->getZpos(),0.0};
	GLfloat dir[]={0.0,0.0,-100.0};
	glLightfv(GL_LIGHT6,GL_POSITION,pos);
	glLightfv(GL_LIGHT6,GL_SPOT_DIRECTION,dir);

	glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,mat_glass);
	glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,mat_glass);
	glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,mat_glass);
	glMaterialfv(GL_FRONT_AND_BACK,GL_SHININESS,mat_glass);
	glMaterialfv(GL_FRONT_AND_BACK,GL_EMISSION,mat_glass);
	glColor4fv(color_glass);


	// Front
	glBegin(GL_QUADS);
	glNormal3f( 0.0f, 0.0f, 1.0f);
	glTexCoord2f(0.0,1.0);
	glVertex3f(-0.5,1.0,-2.0);
	glTexCoord2f(0.0,0.0);
	glVertex3f(-0.5,0.0,-2.0);
	glTexCoord2f(1.0,0.0);
	glVertex3f(0.5,0.0,-2.0);
	glTexCoord2f(1.0,1.0);
	glVertex3f(0.5,1.0,-2.0);
	glEnd();

	//Back
	glBegin(GL_QUADS);
	glNormal3f( 0.0f, 0.0f, -1.0f);
	glTexCoord2f(0.0,1.0);
	glVertex3f(-0.5,1.0,2.0);
	glTexCoord2f(0.0,0.0);
	glVertex3f(-0.5,0.0,2.0);
	glTexCoord2f(1.0,0.0);
	glVertex3f(0.5,0.0,2.0);
	glTexCoord2f(1.0,1.0);
	glVertex3f(0.5,1.0,2.0);
	glEnd();

	//Left
	glBegin(GL_QUADS);
	glNormal3f( 1.0f, 0.0f, 0.0f);
	glTexCoord2f(0.0,1.0);
	glVertex3f(-2.0,1.0,-0.5);
	glTexCoord2f(0.0,0.0);
	glVertex3f(-2.0,0.0,-0.5);
	glTexCoord2f(1.0,0.0);
	glVertex3f(-2.0,0.0,0.5);
	glTexCoord2f(1.0,1.0);
	glVertex3f(-2.0,1.0,0.5);
	glEnd();

	//Right
	glBegin(GL_QUADS);
	glNormal3f(-1.0f, 0.0f, 0.0f);
	glTexCoord2f(0.0,1.0);
	glVertex3f(2.0,1.0,-0.5);
	glTexCoord2f(0.0,0.0);
	glVertex3f(2.0,0.0,-0.5);
	glTexCoord2f(1.0,0.0);
	glVertex3f(2.0,0.0,0.5);
	glTexCoord2f(1.0,1.0);
	glVertex3f(2.0,1.0,0.5);
	glEnd();

	//fig1->rotateX();
	fig1->rotateY();
	//fig1->rotateZ();

	glutSwapBuffers();						// since this is double buffered, swap the buffers to display what just got drawn.
}


void timerCubeFunc(int n){

	fig1->increaseYrot();

	glutPostRedisplay();
	glutTimerFunc(10, &timerCubeFunc, 0);
}



void switchFullScreen(){
	if (fullscreen){
		glutFullScreen();
	} else {
		glutReshapeWindow(640,480);
		glutPositionWindow(0,0);
	}
	fullscreen = !fullscreen;
}

void specialKeyPressed(int key, int x, int y){
	switch (key){
	case GLUT_KEY_F1:
		cout << "blah" << endl;
		switchFullScreen();
		break;

	default:
		specialKeyStates[key] = true;
		break;
	}
}

void specialKeyReleased(int key, int x, int y){
	specialKeyStates[key] = false;
}

void keyPressed(unsigned char key, int x, int y) {
	if (key >= '0' && key <= '9'){
		cout << "light " << key << " is " << !lights[key] << endl;
		lights[key] = !lights[key];
		if(lights[key])
			glEnable(0x4000+key-'0');
		else
			glDisable(0x4000+key-'0');
	}

	switch(key){
	case 'q':
	case 'Q':
	case ESCAPE:
		cout << "Exit." << endl;
		glutDestroyWindow(window);
		exit(0);
		break;

	case 'b':
	case 'B': // switch the blend
		cout << "B/b pressed; blending is: " << blend << endl;
		blend = !blend;              // switch the current value of blend, between 0 and 1.
		if (blend) {
			glEnable(GL_BLEND);
		} else {
			glDisable(GL_BLEND);
		}
		cout << "Blending is now: " << blend << endl;

		break;

	case 'f':
	case 'F': // switch the filter
		cout << "F/f pressed; filter is: " << filter << endl;
		filter++;                           // switch the current value of filter, between 0/1/2;
		if (filter > 2) {
			filter = 0;
		}
		cout << "Filter is now: " << filter << endl;
		break;

	case 'g':
	case 'G': // switch the filter
		cout << "G/g pressed; filter is: " << fogfilter << endl;
		fogfilter++;                           // switch the current value of filter, between 0/1/2;
		if (fogfilter > 2) {
			fogfilter = 0;
		}
		cout << "Filter is now: " << fogfilter << endl;
		glFogi (GL_FOG_MODE, fogMode[fogfilter]);
		break;

	case 'l':
	case 'L':// switch the lighting
		cout << "L/l pressed; lighting is: " << light << endl;
		light = !light;              // switch the current value of light, between 0 and 1.
		if (light) {
			glEnable(GL_LIGHTING);
		} else {
			glDisable(GL_LIGHTING);
		}
		cout << "Lighting is now: " << light << endl;
		break;

	default:
		keyStates[key] = true;
		break;
	}
}

void keyReleased(unsigned char key, int x, int y){
	keyStates[key] = false;
}

void keySpecialoperations(){
	if (specialKeyStates[GLUT_KEY_UP]) 				// look up
		player->LookUp();
	if (specialKeyStates[GLUT_KEY_DOWN]) 			// look down
		player->LookDown();
	if (specialKeyStates[GLUT_KEY_LEFT]) 			// look left
		player->LookLeft();
	if (specialKeyStates[GLUT_KEY_RIGHT]) 			// look right
		player->LookRight();
}

void keyOperations () {
	// WASD
	if(keyStates['w']){
		//cout << "Move forward." << endl;
		player->WalkForward();
	}
	if(keyStates['a']){
		//cout << "Strafe left." << endl;
		player->StrafeLeft();
	}
	if(keyStates['s']){
		//cout << "Move backward." << endl;
		player->WalkBackward();
	}
	if(keyStates['d']){
		//cout << "Strafe right." << endl;
		player->StrafeRight();
	}
}


int main(int argc, char **argv)
{
	player = new Player();
	fig1 = new Figures(F_CUBE,0.0,0.3,-1.0,0.2);

	fig1->increaseXrot(45.0);
	fig1->increaseZrot(45.0);

	for(int i=0; i<256; i++){
		keyStates[i] = false;
		specialKeyStates[i] = false;
	}

	for (int i=0; i<10; i++)
		lights[i]=true;
	lights[0]=false;

	SetupWorld();

	/* Initialize GLUT state - glut will take any command line arguments that pertain to it or
     X Windows - look at its documentation at http://reality.sgi.com/mjk/spec3/spec3.html */
	glutInit(&argc, argv);

	/* Select type of Display mode:
     Double buffer
     RGBA color
     Alpha components supported
     Depth buffer */
	glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_ALPHA | GLUT_DEPTH);

	/* get a 640 x 480 window */
	glutInitWindowSize(640, 480);

	/* the window starts at the upper left corner of the screen */
	glutInitWindowPosition(0, 0);

	/* Open a window */
	window = glutCreateWindow("Jeff Molofee's GL Code Tutorial ... NeHe '99");

	/* Register the function to do all our OpenGL drawing. */
	glutDisplayFunc(&DrawGLScene);

	/* Go fullscreen.  This is as soon as possible. */
	//glutFullScreen();
	fullscreen = false;

	/* Even if there are no events, redraw our gl scene. */
	glutIdleFunc(&DrawGLScene);

	/* Register the function called when our window is resized. */
	glutReshapeFunc(&ReSizeGLScene);

	/* Register the function called when the keyboard is pressed. */
	glutKeyboardFunc(&keyPressed);
	glutKeyboardUpFunc(&keyReleased);

	/* Register the function called when special keys (arrows, page down, etc) are pressed. */
	glutSpecialFunc(&specialKeyPressed);
	glutSpecialUpFunc(&specialKeyReleased);

	/* Timered functions */
	glutTimerFunc(10,&timerCubeFunc,10);

	/* Initialize our window. */
	InitGL(640, 480);

	/* Start Event Processing Engine */
	glutMainLoop();

	return 1;
}

